package com.logica.tutorial.businesslogic;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import com.autobizlogic.abl.annotations.Constraint;
import com.autobizlogic.abl.annotations.CurrentBean;
import com.autobizlogic.abl.engine.ConstraintFailure;
import com.logica.tutorial.model.Person;

public class PersonLogic {
	@CurrentBean
	public Person person;

	@Constraint
	public void checkIdNumber() {
		// String errorMessage = "";
		Long personIdToCheck = person.getId();

		if (personIdToCheck.toString().length() != 11) {
			ConstraintFailure.failConstraint("IdLengthException");
		}

		Integer[] digits = getDigits(personIdToCheck);
		if (!(digits[0] > 0 && digits[0] < 6)) {
			ConstraintFailure.failConstraint("IdFirstNrException");
		}

		if (!verifyBirthDate(digits)) {
			ConstraintFailure.failConstraint("IdBirthDateException");
		}

		if (!verifyCheckSum(digits)) {
			ConstraintFailure.failConstraint("IdCheckSumException");
		}
	};

	public boolean verifyBirthDate(Integer[] digits) {
		int century;
		switch (digits[0]) {
		case 1:
		case 2: {
			century = 1800;
			break;
		}
		case 3:
		case 4: {
			century = 1900;
			break;
		}
		case 5:
		case 6: {
			century = 2000;
			break;
		}
		default: {
			return false;
		}
		}

		int year = century + digits[1] * 10 + digits[2];
		int month = digits[3] * 10 + digits[4];
		int day = digits[5] * 10 + digits[6];

		String date = year + "," + month + "," + day;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy,MM,dd");
		sdf.setLenient(false);

		return sdf.parse(date, new ParsePosition(0)) != null;
	}

	public boolean verifyCheckSum(Integer[] digits) {
		int n = digits[0] * 1 + digits[1] * 2 + digits[2] * 3 + digits[3] * 4
				+ digits[4] * 5 + digits[5] * 6 + digits[6] * 7 + digits[7] * 8
				+ digits[8] * 9 + digits[9] * 1;
		int c = n % 11;

		// special case recalculate the checksum
		if (c == 10) {
			n = digits[0] * 3 + digits[1] * 4 + digits[2] * 5 + digits[3] * 6
					+ digits[4] * 7 + digits[5] * 8 + digits[6] * 9 + digits[7]
					* 1 + digits[8] * 2 + digits[9] * 3;
			c = n % 11;
			c = c % 10;
		}
		return (c == digits[10]);
	}

	public static Integer[] getDigits(Long num) {
		List<Integer> digits = new ArrayList<Integer>();
		collectDigits(num, digits);
		return digits.toArray(new Integer[] {});
	}

	private static void collectDigits(Long num, List<Integer> digits) {
		if (num / 10 > 0) {
			collectDigits(num / 10, digits);
		}
		digits.add((int) (num % 10));
	}
}
